package net.gdface.facelog;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.Sets;
import com.google.common.net.HostAndPort;

import gu.simplemq.IMQConnParameterSupplier;
import gu.simplemq.MessageQueueType;
import gu.simplemq.redis.JedisPoolLazy;
import gu.simplemq.redis.JedisPoolLazy.PropName;
import gu.simplemq.redis.JedisUtils;
import static com.google.common.base.Preconditions.*;
/**
 * 
 * redis管理模块
 * @author guyadong
 *
 */
class RedisManagement implements ServiceConstant,IMQConnParameterSupplier{
	private static final String CMD_PREFIX = "cmd_";
	private static final String TASK_PREFIX = "task_";
	private static final String LOG_MONITOR_PREFIX = "log_monitor_";
	private static final String HEARTBEAT_MONITOR_PREFIX = "hb_monitor_";

	private static final String redisURI;
	/** redis数据库配置参数 */
	private final static Map<PropName, Object> parameters;
	private static String webredisURL = null;
	/** webredis服务参数 */
	private final static Map<String, Object> webredisParameters;
	/** 消息系统(redis)基本参数  */
	private final ImmutableMap<MQParam,String> redisParam ;
	/** 所有任务队列key */
	private static final Set<String> taskKeys = Sets.newConcurrentHashSet();
	static{
		parameters = GlobalConfig.makeRedisParameters();
		webredisParameters = GlobalConfig.makeWebredisParameters();
		JedisPoolLazy.createDefaultInstance(parameters);
		redisURI = JedisPoolLazy.getDefaultInstance().getCanonicalURI().toString();
	}
	private final RedisController redisController = new RedisController(parameters);
	private final WebredisController webredisContoller = new WebredisController(webredisParameters);

	protected RedisManagement() {		
		redisController.init();
		if(MessageQueueType.REDIS.equals(GlobalConfig.getMessageQueueType())){
			webredisContoller.init();
		}
		Builder<MQParam, String> builder = ImmutableMap.<MQParam,String>builder()
			.put(MQParam.REDIS_URI, redisURI)
			.put(MQParam.CMD_CHANNEL, createCmdChannel())
			.put(MQParam.LOG_MONITOR_CHANNEL, createLogMonitorChannel())
			.put(MQParam.HB_MONITOR_CHANNEL, createHeartbeatMonitorChannel())
			.put(MQParam.HB_INTERVAL, CONFIG.getInteger(HEARTBEAT_INTERVAL, DEFAULT_HEARTBEAT_PERIOD).toString())
			.put(MQParam.HB_EXPIRE, CONFIG.getInteger(HEARTBEAT_EXPIRE, DEFAULT_HEARTBEAT_EXPIRE).toString());
		sdkTaskRegister();
		if(!Strings.isNullOrEmpty(webredisURL)){
			builder.put(MQParam.WEBREDIS_URL, webredisURL);
		}
		redisParam = builder.build();
		GlobalConfig.logRedisParameters(JedisPoolLazy.getDefaultInstance().getParameters());
	}
	/** 创建随机命令通道 */
	private String createCmdChannel(){
		return createRandomConstOnRedis(KEY_CMD_CHANNEL,CMD_PREFIX);
	}
	/** 创建随机人员验证实时监控通道名 */
	private String createLogMonitorChannel(){
		return createRandomConstOnRedis(KEY_LOG_MONITOR_CHANNEL,LOG_MONITOR_PREFIX);
	}
	/** 创建随机设备心跳实时监控通道名 */
	private String createHeartbeatMonitorChannel(){
		return createRandomConstOnRedis(KEY_HB_MONITOR_CHANNEL,HEARTBEAT_MONITOR_PREFIX);
	}
	private static String taskKeyOf(String taskname){
		return TASK_PREFIX + taskname + "_";
	}
	/**
	 * 用当前时间生成一个随机的字符串值存到Redis服务器上({@code key})
	 * @param key 常量名 redis上key
	 * @param prefix 随机字符串前缀
	 * @return 生成的随机字符串
	 */
	private String createRandomConstOnRedis(String key,String prefix){
		String timestamp = String.format("%06x", System.nanoTime());
		String v = prefix + timestamp.substring(timestamp.length()-6, timestamp.length());
		return JedisUtils.setnx(key,v);
	}
	/** 返回redis访问参数 */
	protected Map<MQParam,String> getRedisParameters(){
		return this.redisParam;
	}
	@Override
	public final MessageQueueType getImplType(){
		return MessageQueueType.REDIS;
	}
	@Override
	public HostAndPort getHostAndPort() {
		return JedisUtils.getHostAndPort(parameters);
	}

	@Override
	public  HashMap<String, Object> getMQConnParameters(){
		return JedisUtils.asMqParameters(parameters);
	}

	/**
	 * 注册一个任务名<br>
	 * 方法将会根据任务名在redis上生成一个对应的队列<br>
	 * 对同一个任务名多次调用本方法，不会产生不同的队列名字
	 * @param task 任务名
	 * @return 返回保存队列名的key
	 */
	protected String taskRegister(String task) {
		checkArgument(!Strings.isNullOrEmpty(task),"task is empty or null");
		String key = taskKeyOf(task);
		createRandomConstOnRedis(key,key);
		taskKeys.add(key);
		return key;
	}
	/**
	 * 根据任务名返回redis队列名
	 * @param task 任务名
	 * @return 返回redis队列名,队列不存在则返回{@code null}
	 */
	protected String taskQueueOf(String task) {	
		checkArgument(!Strings.isNullOrEmpty(task),"task is empty or null");
		return JedisUtils.get(taskKeyOf(task));
	}
	/**
	 * sdk任务注册 <br>
	 */
	private void sdkTaskRegister() {
		for(String sdkVersion:FeatureConfig.FEATURE_CONFIG.getSdkVersionWhiteList()){
			taskRegister(TASK_FACEAPI_BASE + sdkVersion);
			taskRegister(TASK_REGISTER_BASE + sdkVersion);
			taskRegister(TASK_FEATURE_BASE + sdkVersion);			
		}
	}
	protected String sdkTaskQueueOf(String task,String sdkVersion) {	
		checkArgument(!Strings.isNullOrEmpty(task),"task is empty or null");
		checkArgument(!Strings.isNullOrEmpty(sdkVersion),"sdkVersion is empty or null");
		return taskQueueOf(task + sdkVersion);
	}
	/**
	 * 从任务队列名中解析出SDK版本号<br>
	 * @param taskQueue
	 * @return SDK版本号
	 */
	static String parseSdkVersion(String taskQueue){
		checkArgument(!Strings.isNullOrEmpty(taskQueue),"taskQueue is empty or null");
		Pattern pattern = Pattern.compile(TASK_PREFIX + "(\\w+)_(\\w+)_(\\w+)");
		Matcher matcher = pattern.matcher(taskQueue);
		checkArgument(matcher.matches(),"FAIL TO parse SDK VERSION from taskQueue:%s",taskQueue);
		return matcher.group(2);
	}
}
